package miage.rest.resource.candidature;

import com.thoughtworks.xstream.XStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import java.util.List;

import miage.rest.db.Database;
import miage.rest.form.Form;
import miage.rest.model.Candidat;
import miage.rest.model.Candidature;
import miage.rest.resource.ResourceError;
import miage.rest.routing.UriTemplateFinder;
import miage.rest.security.Roles;
import miage.rest.validation.DateValidator;
import miage.rest.validation.LengthValidator;
import miage.rest.validation.NotEmptyValidator;
import miage.rest.validation.RegexValidator;
import miage.rest.validation.Validator;
import miage.rest.xml.XstreamRepresentation;
import miage.rest.xml.xstream.converter.HrefConverter;
import org.apache.commons.dbutils.DbUtils;

import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Put;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

/**
 * Resource représentant un candidat
 *
 * @author Schwartz Michaël
 */
public class CandidatResource extends ServerResource {

	private final Database database;
	private final UriTemplateFinder uriTemplateFinder;
	private Candidat candidat;

	public CandidatResource(Database database,
							UriTemplateFinder uriTemplateFinder) {
		this.database = database;
		this.uriTemplateFinder = uriTemplateFinder;
	}

	/**
	 * @require getRequest().getAttributes().get("idCandidat") représente un nombre
	 * 
	 * @throws ResourceException
	 */
	@Override
	protected void doInit() throws ResourceException {

		final String sqlCandidat = "SELECT * FROM candidat WHERE id_candidat = ?";
		final String sqlCandidatures = "SELECT id_candidature from candidature WHERE id_candidat = ?";

		Long idCandidat = Long.parseLong(getRequest().getAttributes().get(
				"idCandidat").toString());

		//Validation de l'id du candidat
		if (idCandidat <= 0) {
			getResponse().setEntity(ResourceError.getNewRepresentation("invalidCandidatId"));
			throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST);
		}

		//Récupération du candidat
		try {
			candidat = database.fetchRow(sqlCandidat, Candidat.class, idCandidat);

			if (candidat != null) {

				//Récupération des candidatures du candidat
				List<Candidature> candidatures = database.fetchAll(
						sqlCandidatures, Candidature.class,candidat.getIdCandidat());
				candidat.setCandidatures(candidatures);

			} else {

				//Le candidat n'a pas été trouvé
				setExisting(false);
			}
			
		} catch (SQLException ex) {

			throw new ResourceException(Status.SERVER_ERROR_INTERNAL, ex);
		}

		if (isExisting()) {
			//Validation du role
			if (!isInRole(Roles.ADMIN.getName())) {
				throw new ResourceException(Status.CLIENT_ERROR_UNAUTHORIZED);
			}
		}
	}

	/**
	 * Représentation XML d'un candidat en réponse à une requête GET.
	 *
	 * @require candidat != null
	 */
	@Get
	public Representation doGet() {
		assert (candidat != null);

		Representation response = null;

		//Création d'une représentation XStream du candidat
		response = new XstreamRepresentation<Candidat>(candidat);
		XStream xstream = ((XstreamRepresentation) response).getXstream();

		//Ajout de l'intégration des liens href  pour la classe Candidature
		//par l'intermédiaire de la classe HrefConverter
		xstream.registerConverter(new HrefConverter(
				Candidature.class,
				xstream.getConverterLookup(),
				uriTemplateFinder.find(CandidatureResource.class)));

		return response;
	}

	@Put
	public Representation doPut(Representation entity) throws Exception {
		Representation result = null;
		Connection connexion = null;
		List<ResourceError> errors = new ArrayList<ResourceError>();

		/**
		 * @TODO : il faut que le candidat soit actif
		 */
		try {

			Form form = getPutCandidatForm(entity);
			if (!form.isValid()) {

				for (String error : form.getMessages()) {
					errors.add(new ResourceError(error));
				}
				setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
			} else {

				//Première candidature donc création d'un candidat
				String nom = form.getFirstValue("nom");
				String prenom = form.getFirstValue("prenom");
				String tel1 = form.getFirstValue("tel1");
				String tel2 = form.getFirstValue("tel2");
				String email = form.getFirstValue("email");
				String commentaire = form.getFirstValue("commentaire");
				DateFormat date = new SimpleDateFormat("d/M/y");
				Date date_naissance = new Date(date.parse(form.getFirstValue("dateNaissance")).getTime());
				String lieuNaissance = form.getFirstValue("lieuNaissance");
				String nomMarital = form.getFirstValue("nomMarital");
				String adresse = form.getFirstValue("adresse");
				String codePostal = form.getFirstValue("codePostal");
				String ville = form.getFirstValue("ville");
				String idNationalite = form.getFirstValue("idNationalite");
				String sexe = form.getFirstValue("sexe");

				connexion = database.getNewConnection();
				connexion.setAutoCommit(false);
				
				String sqlCandidat = "UPDTATE candidat SET "
						+ "nom = ?, prenom = ?,email = ? , "
						+ "adresse = ?, code_postal = ?, ville ? , "
						+ "lieu_naissance = ? , nom_marital = ?, tel1 = ?, "
						+ "tel2 = ?, date_naissance = ?, "
						+ "id_nationalite = ?, sexe = ? "
						+ " WHERE id_candidat = ?";
				
				Integer insertedCandidat = database.update(
						connexion,
						sqlCandidat,
						nom, prenom, email,
						adresse, codePostal, ville,
						lieuNaissance, nomMarital, tel1,
						tel2, date_naissance,
						idNationalite, sexe,
						candidat.getIdCandidat()).getGeneratedKeys();
				
				if (insertedCandidat == null || insertedCandidat != candidat.getIdCandidat()) {

					errors.add(new ResourceError("Impossible de modifier le candidat"));
					setStatus(Status.SERVER_ERROR_INTERNAL);

				} else {

					result = new XstreamRepresentation<Candidat>(new Candidat(
							candidat.getIdCandidat()));
					XStream xstream = ((XstreamRepresentation) result).getXstream();
					xstream.registerConverter(new HrefConverter(
							Candidat.class,
							xstream.getConverterLookup(),
							uriTemplateFinder.find(CandidatResource.class)));

					setStatus(Status.SUCCESS_OK);
					connexion.commit();
				}
			}

		} catch (Exception exc) {
			DbUtils.rollbackAndCloseQuietly(connexion);
			if (exc instanceof NumberFormatException) {
				setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
			} else {
				throw exc;
			}
		}
		
		if (!errors.isEmpty()) {
			result = ResourceError.getNewRepresentation(errors);
		}
		
		return result;
	}

	@SuppressWarnings("unchecked")
	private Form getPutCandidatForm(Representation entity) {

		Form form = new Form(entity);
		Validator<String> notEmptyValidator = new NotEmptyValidator();
		Validator<String> lentghValidator100 = new LengthValidator(100);
		Validator<String> lentghValidator50 = new LengthValidator(50);
		Validator<String> namesValidator = new RegexValidator(
				"^([a-zA-Z'àâéèêëîïôùûçÀÂÉÈÔÙÛÇ\\s-]{1,100})$");
		Validator<String> emailValidator = new RegexValidator(
				"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$");
		Validator<String> dateValidator = new DateValidator("d/m/y",
															"jj/mm/aaaa");

		//Récupération du nom, prénom et ajout de validateurs pour tester si le nom est vide et s'il valide une regex
		form.addValidators("nom", notEmptyValidator, namesValidator);
		form.addValidators("prenom", notEmptyValidator, namesValidator);
		form.addValidator("tel1", lentghValidator50);
		form.addValidator("tel2", lentghValidator50);
		form.addValidators("email", notEmptyValidator, lentghValidator50, emailValidator);
		form.addValidators("dateNaissance", notEmptyValidator, dateValidator);
		form.addValidator("lieuNaissance", lentghValidator100);
		form.addValidator("nomMarital", lentghValidator100);
		form.addValidator("adresse", notEmptyValidator);
		form.addValidators("codePostal", notEmptyValidator, new LengthValidator(10));
		form.addValidators("ville", notEmptyValidator, lentghValidator50);
		form.addValidator("idNationalite", new LengthValidator(5));
		form.addValidator("sexe", new LengthValidator(20));
		form.addValidator("commentaire", new LengthValidator(250));

		return form;
	}
}
